<template>
    <div class="scroll-container" ref="scrollContainer" @scroll="handleScroll">
        <div class="placeholder" :style="{ height: totalHeight + 'px' }"></div>
        <div class="items-container" :style="{ transform: `translateY(${offset}px)` }">
            <div v-for="item in visibleData" :key="item.id" class="item">
                {{ item.text }}
            </div>
        </div>
    </div>
</template>

<script>
export default {
    name: "VirtualScroll",
    props: {
        // 数据列表
        InitData: {
            type: Array,
            default: () => [],
        },
        // 预加载条数
        buffer: {
            type: Number,
            default: 2,
        },
    },
    data() {
        return {
            visibleCount: 0, // 可以显示多少条（根据容器高度计算，或者父组件传入,目的装满容器）

            itemHeight: 30, // 每一项的高度
            startIndex: 0, // 开始索引
            scrollTop: 0, // 滚动条位置
        }
    },
    mounted() {
        this.$nextTick(() => {
            this.visibleCount = Math.ceil(this.$refs.scrollContainer.clientHeight / this.itemHeight)
        })
    },
    computed: {
        // 计算结束索引
        endIndex() {
            // 开始索引+可见条数+预加载条数   不得大于数组长度
            return Math.min(this.startIndex + this.visibleCount + this.buffer, this.InitData.length)
        },
        // 计算可见数据
        visibleData() {
            // 可见数据 = 列表数据.slice(开始索引,结束索引)
            return this.InitData.slice(Math.max(0, this.startIndex - this.buffer), this.endIndex)
        },
        // 容器总高度（模拟高度，显示滚动条用）
        totalHeight() {
            return this.InitData.length * this.itemHeight
        },
        // 定位位置
        offset() {
            return Math.max(0, this.startIndex - this.buffer) * this.itemHeight
        },
    },
    methods: {
        handleScroll() {
            const container = this.$refs.scrollContainer
            this.scrollTop = container?.scrollTop
            this.startIndex = Math.floor(this.scrollTop / this.itemHeight)
        },
    },
}
</script>

<style lang="scss" scoped>
.scroll-container {
    height: calc(100% - 30px);
    overflow-y: auto;
    position: relative;
    .placeholder {
        position: absolute;
        top: 0;
        left: 0;
        right: 0;
    }
    .items-container {
        position: absolute;
        width: 100%;
        .item {
            height: 30px;
            line-height: 30px;
            text-align: center;
            border-bottom: 1px solid #ccc;
        }
    }
}
</style>
